home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / DKBSRC.ARJ / LIGHTING.C < prev    next >
C/C++ Source or Header  |  1991-05-04  |  28KB  |  835 lines

  1. /*****************************************************************************
  2. *
  3. *                                    lighting.c
  4. *
  5. *   from DKBTrace (c) 1990  David Buck
  6. *
  7. *  This module calculates lighting properties like ambient, diffuse, specular,
  8. *  reflection, refraction, etc.
  9. *
  10. *
  11. * This software is freely distributable. The source and/or object code may be
  12. * copied or uploaded to communications services so long as this notice remains
  13. * at the top of each file.  If any changes are made to the program, you must
  14. * clearly indicate in the documentation and in the programs startup message
  15. * who it was who made the changes. The documentation should also describe what
  16. * those changes were. This software may not be included in whole or in
  17. * part into any commercial package without the express written consent of the
  18. * author.  It may, however, be included in other public domain or freely
  19. * distributed software so long as the proper credit for the software is given.
  20. *
  21. * This software is provided as is without any guarantees or warranty. Although
  22. * the author has attempted to find and correct any bugs in the software, he
  23. * is not responsible for any damage caused by the use of the software.  The
  24. * author is under no obligation to provide service, corrections, or upgrades
  25. * to this package.
  26. *
  27. * Despite all the legal stuff above, if you do find bugs, I would like to hear
  28. * about them.  Also, if you have any comments or questions, you may contact me
  29. * at the following address:
  30. *
  31. *     David Buck
  32. *     22C Sonnet Cres.
  33. *     Nepean Ontario
  34. *     Canada, K2H 8W7
  35. *
  36. *  I can also be reached on the following bulleton boards:
  37. *
  38. *     OMX              (613) 731-3419
  39. *     Mystic           (613) 596-4249  or  (613) 596-4772
  40. *
  41. *  Fidonet:   1:163/109.9
  42. *  Internet:  dbuck@ccs.carleton.ca
  43. *  The "You Can Call Me RAY" BBS    (708) 358-5611
  44. *
  45. *  IBM Port by Aaron A. Collins. Aaron may be reached on the following BBS'es:
  46. *
  47. *     The "You Can Call Me RAY" BBS (708) 358-5611
  48. *     The Information Exchange BBS  (708) 945-5575
  49. *
  50. *****************************************************************************/
  51.  
  52.  
  53. #include "frame.h"
  54. #include "vector.h"
  55. #include "dkbproto.h"
  56.  
  57. extern int Trace_Level;
  58. extern FRAME Frame;
  59. extern unsigned long Options;
  60. extern int Quality;
  61. extern long Shadow_Ray_Tests, Shadow_Rays_Succeeded;
  62. extern long Reflected_Rays_Traced, Refracted_Rays_Traced;
  63. extern long Transmitted_Rays_Traced;
  64.  
  65. #define COORDINATE_LIMIT 1.0e17
  66.  
  67. void Colour_At (Colour, Texture, Intersection_Point)
  68.    COLOUR *Colour;
  69.    TEXTURE *Texture;
  70.    VECTOR *Intersection_Point;
  71.    {
  72.    register DBL x, y, z;
  73.    VECTOR Transformed_Point;
  74.  
  75.  
  76.    if ((Intersection_Point->x > COORDINATE_LIMIT) ||
  77.        (Intersection_Point->y > COORDINATE_LIMIT) ||
  78.        (Intersection_Point->z > COORDINATE_LIMIT) ||
  79.        (Intersection_Point->x < -COORDINATE_LIMIT) ||
  80.        (Intersection_Point->y < -COORDINATE_LIMIT) ||
  81.        (Intersection_Point->z < -COORDINATE_LIMIT))
  82.       {
  83.       Make_Vector (&Transformed_Point, 0.0, 0.0, 0.0);
  84.       }
  85.    else
  86.       if (Texture->Texture_Transformation) {
  87.          MInverseTransformVector (&Transformed_Point,
  88.                                   Intersection_Point,
  89.                               Texture->Texture_Transformation);
  90.          }
  91.       else {
  92.          Transformed_Point = *Intersection_Point;
  93.          }
  94.  
  95.    x = Transformed_Point.x;
  96.    y = Transformed_Point.y;
  97.    z = Transformed_Point.z;
  98.  
  99.    switch (Texture->Texture_Number) {
  100.       case NO_TEXTURE:
  101.            /* No colouring texture has been specified - make it black. */
  102.            Make_Colour (Colour, 0.0, 0.0, 0.0);
  103.            Colour -> Alpha  = 0.0;
  104.            break;
  105.  
  106.       case COLOUR_TEXTURE:
  107.            Colour -> Red += Texture->Colour1->Red;
  108.            Colour -> Green += Texture->Colour1->Green;
  109.            Colour -> Blue += Texture->Colour1->Blue;
  110.            Colour -> Alpha += Texture->Colour1->Alpha;
  111.            break;
  112.  
  113.       case BOZO_TEXTURE: 
  114.            Bozo (x, y, z, Texture, Colour);
  115.            break;
  116.  
  117.       case MARBLE_TEXTURE:
  118.            marble (x, y, z, Texture, Colour);
  119.            break;
  120.  
  121.       case WOOD_TEXTURE:
  122.            wood (x, y, z, Texture, Colour);
  123.            break;
  124.  
  125.       case CHECKER_TEXTURE:
  126.            checker (x, y, z, Texture, Colour);
  127.            break;
  128.  
  129.       case CHECKER_TEXTURE_TEXTURE:
  130.            checker_texture (x, y, z, Texture, Colour);
  131.            break;
  132.  
  133.       case SPOTTED_TEXTURE:
  134.            spotted (x, y, z, Texture, Colour);
  135.            break;
  136.  
  137.       case AGATE_TEXTURE:
  138.            agate (x, y, z, Texture, Colour);
  139.            break;
  140.  
  141.       case GRANITE_TEXTURE:
  142.            granite (x, y, z, Texture, Colour);
  143.            break;
  144.  
  145.       case GRADIENT_TEXTURE:
  146.            gradient (x, y, z, Texture, Colour);
  147.            break;
  148.  
  149.       case IMAGEMAP_TEXTURE:
  150.            texture_map (x, y, z, Texture, Colour);
  151.        break;
  152.       }
  153.    }
  154.  
  155.  
  156. void Perturb_Normal(New_Normal, Texture, Intersection_Point, Surface_Normal)
  157.    VECTOR *New_Normal, *Intersection_Point, *Surface_Normal;
  158.    TEXTURE *Texture;
  159.    {
  160.    VECTOR Transformed_Point;
  161.    register DBL x, y, z;
  162.  
  163.    if (Texture->Bump_Number == NO_BUMPS) {
  164.       *New_Normal = *Surface_Normal;
  165.       return;
  166.       }
  167.  
  168.    if (Texture->Texture_Transformation)
  169.       MInverseTransformVector (&Transformed_Point,
  170.                                Intersection_Point,
  171.                                Texture->Texture_Transformation);
  172.    else
  173.       Transformed_Point = *Intersection_Point;
  174.  
  175.    x = Transformed_Point.x;
  176.    y = Transformed_Point.y;
  177.    z = Transformed_Point.z;
  178.  
  179.    switch (Texture->Bump_Number) {
  180.       case NO_BUMPS: break;
  181.  
  182.       case WAVES: waves (x, y, z, Texture, New_Normal);
  183.                   break;
  184.  
  185.       case RIPPLES: ripples (x, y, z, Texture, New_Normal);
  186.                   break;
  187.  
  188.       case WRINKLES: wrinkles (x, y, z, Texture, New_Normal);
  189.                   break;
  190.  
  191.       case BUMPS: bumps (x, y, z, Texture, New_Normal);
  192.                   break;
  193.  
  194.       case DENTS: dents (x, y, z, Texture, New_Normal);
  195.                   break;
  196.       }
  197.    return;
  198.    }
  199.  
  200. void Ambient (Texture, Intersection_Point, Surface_Colour, Colour)
  201.    TEXTURE *Texture;
  202.    VECTOR *Intersection_Point;
  203.    COLOUR *Surface_Colour;
  204.    COLOUR *Colour;
  205.    {
  206.    if (Texture -> Object_Ambient == 0.0)
  207.       return;
  208.  
  209.    Colour->Red += Surface_Colour->Red * Texture->Object_Ambient;
  210.    Colour->Green += Surface_Colour->Green * Texture->Object_Ambient;
  211.    Colour->Blue += Surface_Colour->Blue * Texture->Object_Ambient;
  212.    return;
  213.    }
  214.  
  215.  
  216. void Diffuse (Texture, Intersection_Point, Eye, Surface_Normal, Surface_Colour, Colour)
  217.    TEXTURE *Texture;
  218.    VECTOR *Intersection_Point, *Surface_Normal;
  219.    COLOUR *Surface_Colour;
  220.    COLOUR *Colour;
  221.    RAY *Eye;
  222.    {
  223.    DBL Light_Source_Depth;
  224.    RAY Light_Source_Ray;
  225.    OBJECT *Light_Source, *Blocking_Object;
  226.    int Intersection_Found;
  227.    INTERSECTION *Local_Intersection;
  228.    VECTOR REye;
  229.    COLOUR Light_Colour;
  230.    PRIOQ *Local_Queue;
  231.  
  232.    if ((Texture -> Object_Diffuse == 0.0) &&
  233.        (Texture -> Object_Specular == 0.0) &&
  234.        (Texture -> Object_Phong == 0.0))
  235.      return;
  236.  
  237.    if (Texture -> Object_Specular != 0.0)
  238.       {
  239.       REye.x = -Eye->Direction.x;
  240.       REye.y = -Eye->Direction.y;
  241.       REye.z = -Eye->Direction.z;
  242.       }
  243.  
  244.    Local_Queue = pq_new (128);
  245.  
  246.    for (Light_Source = Frame.Light_Sources ; 
  247.         Light_Source != NULL;
  248.         Light_Source = Light_Source -> Next_Light_Source)
  249.       {
  250.       /* Get the light source colour. */
  251.       if (Light_Source->Object_Colour == NULL) {
  252.          Make_Colour (&Light_Colour, 1.0, 1.0, 1.0);
  253.          }
  254.       else
  255.          Light_Colour = *Light_Source->Object_Colour;
  256.  
  257.       Intersection_Found = FALSE;
  258.  
  259.       do_light(Light_Source, &Light_Source_Depth, &Light_Source_Ray, Intersection_Point);
  260.  
  261.       /* What objects does this ray intersect? */
  262.       if (Quality > 3)
  263.          for (Blocking_Object = Frame.Objects ; 
  264.               Blocking_Object != NULL ;
  265.               Blocking_Object = Blocking_Object -> Next_Object) {
  266.  
  267.             Shadow_Ray_Tests++;
  268.             if (Blocking_Object == Light_Source)
  269.                continue;
  270.  
  271.             for (All_Intersections (Blocking_Object, &Light_Source_Ray, Local_Queue) ;
  272.                  (Local_Intersection = pq_get_highest(Local_Queue)) != NULL ;
  273.                  pq_delete_highest(Local_Queue)) {
  274.  
  275.                if ((Local_Intersection->Object != Light_Source)
  276.                     && (Local_Intersection -> Depth < Light_Source_Depth-Small_Tolerance)
  277.                     && (Local_Intersection -> Depth > Small_Tolerance))
  278.                   {
  279.                   Shadow_Rays_Succeeded++;
  280.                do_blocking(Local_Intersection->Object, Local_Intersection, &Light_Colour);
  281.  
  282.  
  283.                   if ((Light_Colour.Red < 0.01)
  284.                       && (Light_Colour.Green < 0.01)
  285.                       && (Light_Colour.Blue < 0.01)) {
  286.  
  287.                      while (pq_get_highest(Local_Queue))
  288.                         pq_delete_highest(Local_Queue);
  289.                      Intersection_Found = TRUE;
  290.                      break;
  291.                      } 
  292.                   }
  293.                }
  294.             if (Intersection_Found)
  295.                break;
  296.             }
  297.  
  298.       if (!Intersection_Found) {
  299.          if (Texture->Object_Phong >0.0) /*Phong Spec. Hilite*/
  300.         do_phong(Texture,&Light_Source_Ray,Eye->Direction,Surface_Normal,Colour,&Light_Colour, Surface_Colour);
  301.  
  302.          if (Texture->Object_Specular >0.0) /*specular hilite*/
  303.         do_specular(Texture,&Light_Source_Ray,REye,Surface_Normal,Colour,&Light_Colour, Surface_Colour);
  304.  
  305.          if (Texture->Object_Diffuse > 0.0) /*normal diffuse */
  306.         do_diffuse(Texture,&Light_Source_Ray,Surface_Normal,Colour,&Light_Colour,Surface_Colour);
  307.          }
  308.       }
  309.    pq_free (Local_Queue);
  310.    return;
  311.    }
  312.  
  313. void do_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Intersection_Point)
  314. OBJECT *Light_Source;
  315. DBL *Light_Source_Depth;
  316. RAY *Light_Source_Ray;
  317. VECTOR *Intersection_Point;
  318. {
  319.       Light_Source_Ray->Initial = *Intersection_Point;
  320.       Light_Source_Ray->Quadric_Constants_Cached = FALSE;
  321.  
  322.       VSub (Light_Source_Ray->Direction,
  323.            Light_Source->Object_Center,
  324.        *Intersection_Point);
  325.  
  326.       VLength (*Light_Source_Depth, Light_Source_Ray->Direction);
  327.  
  328.       VScale (Light_Source_Ray->Direction, Light_Source_Ray->Direction,
  329.                 1.0/(*Light_Source_Depth));
  330.       return;
  331. }
  332.  
  333. void do_blocking(Blocking_Object, Local_Intersection, Light_Colour)
  334.    OBJECT *Blocking_Object;
  335.    INTERSECTION *Local_Intersection;
  336.    COLOUR *Light_Colour;
  337.    {
  338.    Determine_Surface_Colour (Local_Intersection, Light_Colour, NULL, TRUE);
  339.    return;
  340.    }
  341.  
  342. void do_phong(Texture, Light_Source_Ray, Eye, Surface_Normal, Colour, Light_Colour, Surface_Colour)
  343. TEXTURE *Texture;
  344. RAY *Light_Source_Ray;
  345. VECTOR *Surface_Normal, Eye;
  346. COLOUR *Colour, *Light_Colour, *Surface_Colour;
  347. {
  348.     DBL Cos_Angle_Of_Incidence, Normal_Length, Intensity;
  349.     VECTOR Local_Normal, Normal_Projection, Reflect_Direction;
  350.  
  351.     VDot(Cos_Angle_Of_Incidence, Eye, *Surface_Normal);
  352.  
  353.     if (Cos_Angle_Of_Incidence < 0.0)
  354.     {
  355.         Local_Normal = *Surface_Normal;
  356.         Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
  357.     }
  358.     else
  359.     {
  360.         VScale (Local_Normal, *Surface_Normal, -1.0);
  361.     }
  362.  
  363.     VScale (Normal_Projection, Local_Normal, Cos_Angle_Of_Incidence);
  364.     VScale (Normal_Projection, Normal_Projection, 2.0);
  365.     VAdd (Reflect_Direction, Eye, Normal_Projection);
  366.  
  367.     VDot (Cos_Angle_Of_Incidence, Reflect_Direction, Light_Source_Ray->Direction);
  368.     VLength (Normal_Length, Light_Source_Ray->Direction);
  369.     
  370.     if (Normal_Length == 0.0)
  371.         Cos_Angle_Of_Incidence = 0.0;
  372.     else Cos_Angle_Of_Incidence /= Normal_Length;
  373.  
  374.     if (Cos_Angle_Of_Incidence < 0.0)
  375.         Cos_Angle_Of_Incidence = 0;
  376.  
  377.     if (Texture -> Object_PhongSize != 1.0)
  378.         Intensity = pow(Cos_Angle_Of_Incidence, Texture->Object_PhongSize);
  379.     else
  380.         Intensity = Cos_Angle_Of_Incidence;
  381.  
  382.     Intensity *= Texture -> Object_Phong;
  383.  
  384.         if (Texture->Metallic_Flag) {
  385.        Colour->Red+=Intensity*(Surface_Colour->Red);
  386.        Colour->Green+=Intensity*(Surface_Colour->Green);
  387.        Colour->Blue+=Intensity*(Surface_Colour->Blue);
  388.            }
  389.         else {
  390.        Colour->Red+=Intensity*(Light_Colour->Red);
  391.        Colour->Green+=Intensity*(Light_Colour->Green);
  392.        Colour->Blue+=Intensity*(Light_Colour->Blue);
  393.            }
  394.     return;
  395. }
  396.  
  397. void do_specular(Texture, Light_Source_Ray, REye, Surface_Normal, Colour, Light_Colour, Surface_Colour)
  398. TEXTURE *Texture;
  399. RAY *Light_Source_Ray;
  400. VECTOR *Surface_Normal, REye;
  401. COLOUR *Colour, *Light_Colour, *Surface_Colour;
  402. {
  403.     DBL Cos_Angle_Of_Incidence, Normal_Length, Intensity, Halfway_Length, Roughness;
  404.     VECTOR Halfway;
  405.  
  406.     VHalf (Halfway, REye, Light_Source_Ray->Direction);
  407.     VLength (Normal_Length, *Surface_Normal);
  408.     VLength (Halfway_Length, Halfway);
  409.     VDot (Cos_Angle_Of_Incidence, Halfway, *Surface_Normal);
  410.  
  411.     if (Normal_Length == 0.0 || Halfway_Length == 0.0)
  412.         Cos_Angle_Of_Incidence = 0.0;
  413.     else Cos_Angle_Of_Incidence /= (Normal_Length * Halfway_Length);
  414.  
  415.     if (Cos_Angle_Of_Incidence < 0.0)
  416.         Cos_Angle_Of_Incidence = 0.0;
  417.  
  418.     Roughness = 1.0 / Texture->Object_Roughness;
  419.  
  420.     if (Roughness != 1.0)
  421.         Intensity = pow(Cos_Angle_Of_Incidence, Roughness);
  422.     else
  423.         Intensity = Cos_Angle_Of_Incidence;
  424.  
  425.     Intensity *= Texture->Object_Specular;
  426.  
  427.         if (Texture->Metallic_Flag) {
  428.        Colour->Red+=Intensity*(Surface_Colour->Red);
  429.        Colour->Green+=Intensity*(Surface_Colour->Green);
  430.        Colour->Blue+=Intensity*(Surface_Colour->Blue);
  431.            }
  432.         else {
  433.        Colour->Red+=Intensity*(Light_Colour->Red);
  434.        Colour->Green+=Intensity*(Light_Colour->Green);
  435.        Colour->Blue+=Intensity*(Light_Colour->Blue);
  436.            }
  437.     return;
  438. }
  439.  
  440. void do_diffuse(Texture, Light_Source_Ray, Surface_Normal, Colour, Light_Colour, Surface_Colour)
  441. TEXTURE *Texture;
  442. RAY *Light_Source_Ray;
  443. VECTOR *Surface_Normal;
  444. COLOUR *Colour, *Light_Colour, *Surface_Colour;
  445. {
  446.     DBL Cos_Angle_Of_Incidence, Intensity, RandomNumber;
  447.  
  448.     VDot (Cos_Angle_Of_Incidence, *Surface_Normal, Light_Source_Ray->Direction);
  449.     if (Cos_Angle_Of_Incidence < 0.0)
  450.         Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
  451.  
  452.     if (Texture -> Object_Brilliance != 1.0)
  453.         Intensity = pow(Cos_Angle_Of_Incidence, Texture->Object_Brilliance);
  454.     else
  455.         Intensity = Cos_Angle_Of_Incidence;
  456.  
  457.     Intensity *= Texture -> Object_Diffuse;
  458.  
  459.     RandomNumber = (rand()&0x7FFF)/(DBL) 0x7FFF;
  460.  
  461.     Intensity -= RandomNumber * Texture->Texture_Randomness;
  462.     Colour->Red += Intensity * (Surface_Colour->Red) * (Light_Colour->Red);
  463.     Colour->Green += Intensity * (Surface_Colour->Green) * (Light_Colour->Green);
  464.     Colour->Blue += Intensity * (Surface_Colour->Blue) * (Light_Colour->Blue);
  465.     return;
  466. }
  467.  
  468. void Reflect (Texture, Intersection_Point, Ray, Surface_Normal, Colour)
  469.    TEXTURE *Texture;
  470.    VECTOR *Intersection_Point;
  471.    RAY *Ray;
  472.    VECTOR *Surface_Normal;
  473.    COLOUR *Colour;
  474.    {
  475.    RAY New_Ray;
  476.    COLOUR Temp_Colour;
  477.    VECTOR Local_Normal;
  478.    VECTOR Normal_Projection;
  479.    register DBL Normal_Component;
  480.  
  481.    if (Texture -> Object_Reflection != 0.0)
  482.       {
  483.       Reflected_Rays_Traced++;
  484.       VDot (Normal_Component, Ray -> Direction, *Surface_Normal);
  485.       if (Normal_Component < 0.0) {
  486.          Local_Normal = *Surface_Normal;
  487.          Normal_Component *= -1.0;
  488.          }
  489.       else
  490.          VScale (Local_Normal, *Surface_Normal, -1.0);
  491.  
  492.       VScale (Normal_Projection, Local_Normal, Normal_Component);
  493.       VScale (Normal_Projection, Normal_Projection, 2.0);
  494.       VAdd (New_Ray.Direction, Ray -> Direction, Normal_Projection);
  495.       New_Ray.Initial = *Intersection_Point;
  496.  
  497.       Copy_Ray_Containers (&New_Ray, Ray);
  498.       Trace_Level++;
  499.       Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
  500.       New_Ray.Quadric_Constants_Cached = FALSE;
  501.       Trace (&New_Ray, &Temp_Colour);
  502.       Trace_Level--;
  503.  
  504.       (Colour -> Red) += (Temp_Colour.Red) 
  505.                              * (Texture -> Object_Reflection);
  506.       (Colour -> Green) += (Temp_Colour.Green)
  507.                              * (Texture -> Object_Reflection);
  508.       (Colour -> Blue) += (Temp_Colour.Blue)
  509.                              * (Texture -> Object_Reflection);
  510.       }
  511.    }
  512.  
  513. void Refract (Texture, Intersection_Point, Ray, Surface_Normal, Colour)
  514.    TEXTURE *Texture;
  515.    VECTOR *Intersection_Point;
  516.    RAY *Ray;
  517.    VECTOR *Surface_Normal;
  518.    COLOUR *Colour;
  519.    {
  520.    RAY New_Ray;
  521.    COLOUR Temp_Colour;
  522.    VECTOR Local_Normal;
  523.    VECTOR Normal_Projection;
  524.    register DBL Normal_Component, Temp_IOR;
  525.  
  526.    if (Surface_Normal == NULL) {
  527.       New_Ray.Initial = *Intersection_Point;
  528.       New_Ray.Direction = Ray->Direction;
  529.  
  530.       Copy_Ray_Containers (&New_Ray, Ray);
  531.       Trace_Level++;
  532.       Transmitted_Rays_Traced++;
  533.       Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
  534.       New_Ray.Quadric_Constants_Cached = FALSE;
  535.       Trace (&New_Ray, &Temp_Colour);
  536.       Trace_Level--;
  537.       (Colour -> Red) += Temp_Colour.Red;
  538.       (Colour -> Green) += Temp_Colour.Green;
  539.       (Colour -> Blue) += Temp_Colour.Blue;
  540.       }
  541.    else {
  542.       Refracted_Rays_Traced++;
  543.       VDot (Normal_Component, Ray -> Direction, *Surface_Normal);
  544.       if (Normal_Component >= 0.0)
  545.          {
  546.          VScale (Local_Normal, *Surface_Normal, -1.0);
  547.          }
  548.       else
  549.          {
  550.          Local_Normal.x = Surface_Normal -> x;
  551.          Local_Normal.y = Surface_Normal -> y;
  552.          Local_Normal.z = Surface_Normal -> z;
  553.  
  554.          Normal_Component *= -1.0;
  555.          }
  556.  
  557.       VScale (Normal_Projection, Local_Normal, Normal_Component);
  558.       VAdd (Normal_Projection, Normal_Projection, Ray -> Direction);
  559.       Copy_Ray_Containers (&New_Ray, Ray);
  560.  
  561.       if (Ray -> Containing_Index == -1)
  562.          {
  563.       /* The ray is entering from the atmosphere */
  564.          Ray_Enter (&New_Ray, Texture);
  565.  
  566.          VScale (Normal_Projection, Normal_Projection,
  567.                (Frame.Atmosphere_IOR)/(Texture -> Object_Index_Of_Refraction));
  568.          }
  569.       else
  570.          {
  571.        /* The ray is currently inside an object */
  572.          if (New_Ray.Containing_Textures [New_Ray.Containing_Index] == Texture)
  573.             {
  574.           /* The ray is leaving the current object */
  575.             Ray_Exit (&New_Ray);
  576.             if (New_Ray.Containing_Index == -1)
  577.              /* The ray is leaving into the atmosphere */
  578.                Temp_IOR = Frame.Atmosphere_IOR;
  579.             else
  580.              /* The ray is leaving into another object */
  581.                Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
  582.  
  583.             VScale (Normal_Projection, Normal_Projection,
  584.                (Texture -> Object_Index_Of_Refraction) / Temp_IOR);
  585.             }
  586.          else
  587.             {
  588.             /* The ray is entering a new object */
  589.             Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
  590.             Ray_Enter (&New_Ray, Texture);
  591.  
  592.             VScale (Normal_Projection, Normal_Projection,
  593.                  Temp_IOR/(Texture -> Object_Index_Of_Refraction));
  594.  
  595.             }
  596.          }
  597.  
  598.       VScale (Local_Normal, Local_Normal, -1.0);
  599.       VAdd (New_Ray.Direction, Local_Normal, Normal_Projection);
  600.       VNormalize (New_Ray.Direction, New_Ray.Direction);
  601.       New_Ray.Initial = *Intersection_Point;
  602.       Trace_Level++;
  603.       Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
  604.       New_Ray.Quadric_Constants_Cached = FALSE;
  605.  
  606.       Trace (&New_Ray, &Temp_Colour);
  607.       Trace_Level--;
  608.  
  609.       (Colour -> Red) += (Temp_Colour.Red)
  610.                         * (Texture -> Object_Refraction);
  611.       (Colour -> Green) += (Temp_Colour.Green)
  612.                         * (Texture -> Object_Refraction);
  613.       (Colour -> Blue) += (Temp_Colour.Blue)
  614.                         * (Texture -> Object_Refraction);
  615.       }
  616.    }
  617.  
  618. void Fog (Distance, Fog_Colour, Fog_Distance, Colour)
  619.    DBL Distance, Fog_Distance;
  620.    COLOUR *Fog_Colour, *Colour;
  621.    {
  622.    DBL Fog_Factor, Fog_Factor_Inverse;
  623.  
  624.    Fog_Factor = exp(-1.0 * Distance/Fog_Distance);
  625.    Fog_Factor_Inverse = 1.0 - Fog_Factor;
  626.    Colour->Red = Colour->Red*Fog_Factor + Fog_Colour->Red*Fog_Factor_Inverse;
  627.    Colour->Green = Colour->Green*Fog_Factor + Fog_Colour->Green*Fog_Factor_Inverse;
  628.    Colour->Blue = Colour->Blue*Fog_Factor + Fog_Colour->Blue*Fog_Factor_Inverse;
  629.    }
  630.  
  631.  
  632.  
  633. void Compute_Reflected_Colour (Ray, Texture, Ray_Intersection, Surface_Colour, Emitted_Colour)
  634.    RAY *Ray;
  635.    TEXTURE *Texture;
  636.    INTERSECTION *Ray_Intersection;
  637.    COLOUR *Surface_Colour;
  638.    COLOUR *Emitted_Colour;
  639.    {
  640.    VECTOR Surface_Normal;
  641.    DBL Normal_Direction;
  642.  
  643.    /* This variable keeps track of how much colour comes from the surface
  644.       of the object and how much is transmited through. */
  645.  
  646.    Make_Colour (Emitted_Colour, 0.0, 0.0, 0.0);
  647.  
  648.    if (Texture == NULL)
  649.       Texture = Ray_Intersection->Object->Object_Texture;
  650.       
  651.    if (Quality <= 1) {
  652.       *Emitted_Colour = *Surface_Colour;
  653.       Surface_Colour->Alpha = 0.0;
  654.       return;
  655.       }
  656.  
  657.    Normal (&Surface_Normal, (OBJECT *) Ray_Intersection -> Shape,
  658.            &Ray_Intersection -> Point);
  659.       
  660.    if (Quality >= 8) {
  661.       Perturb_Normal (&Surface_Normal, Texture,
  662.                       &Ray_Intersection->Point, &Surface_Normal);
  663.       }
  664.  
  665.    /* If the surface normal points away, flip its direction. */
  666.    VDot (Normal_Direction, Surface_Normal, Ray->Direction);
  667.    if (Normal_Direction > 0.0) {
  668.       VScale (Surface_Normal, Surface_Normal, -1.0);
  669.       }
  670.          
  671.    Ambient (Texture, &Ray_Intersection -> Point,
  672.             Surface_Colour, Emitted_Colour);
  673.  
  674.    Diffuse (Texture, &Ray_Intersection -> Point, Ray,
  675.             &Surface_Normal, Surface_Colour, Emitted_Colour);
  676.          
  677.    if (Quality >= 8)
  678.       Reflect (Texture, &Ray_Intersection -> Point, Ray,
  679.                &Surface_Normal, Emitted_Colour);
  680.    }
  681.  
  682. void Determine_Surface_Colour (Ray_Intersection, Colour, Ray, Shadow_Ray)
  683.    INTERSECTION *Ray_Intersection;
  684.    COLOUR *Colour;
  685.    RAY *Ray;
  686.    int Shadow_Ray;
  687.    {
  688.    COLOUR Emitted_Colour, Surface_Colour, Refracted_Colour, Filter_Colour;
  689.    TEXTURE *Temp_Texture, *Texture;
  690.    VECTOR Surface_Normal;
  691.    DBL Normal_Direction, S_Alpha;
  692.    int surface;
  693.  
  694.    if (!Shadow_Ray)
  695.       Make_Colour (Colour, 0.0, 0.0, 0.0);
  696.  
  697.    if (Options & DEBUGGING)
  698.       if (Ray_Intersection->Shape->Shape_Colour)
  699.          printf ("Depth: %f Object %d Colour %f %f %f ", Ray_Intersection->Depth,
  700.                  Ray_Intersection->Shape->Type,
  701.                  Ray_Intersection->Shape->Shape_Colour->Red,
  702.                  Ray_Intersection->Shape->Shape_Colour->Green,
  703.                  Ray_Intersection->Shape->Shape_Colour->Blue);
  704.       else
  705.          printf ("Depth: %f Object %d Colour NIL ", Ray_Intersection->Depth,
  706.                  Ray_Intersection->Shape->Type);
  707.  
  708.  
  709.    Make_Colour (&Surface_Colour, 0.0, 0.0, 0.0);
  710.  
  711.    /* Is there a texture in the shape?  If not, use the one in the object. */
  712.    if ((Texture = Ray_Intersection->Shape->Shape_Texture) == NULL) {
  713.       Texture = Ray_Intersection->Object->Object_Texture;      
  714.       }
  715.  
  716.    /* If this is just a shadow ray and we're rendering low quality, then return */
  717.  
  718.    if (Shadow_Ray && (Quality <= 5))
  719.       return;
  720.  
  721.    Make_Colour (&Filter_Colour, 1.0, 1.0, 1.0);
  722.    Filter_Colour.Alpha = 1.0;
  723.  
  724.    /* Now, we perform the lighting calculations. */
  725.    for ( surface = 1 , Temp_Texture = Texture;
  726.         (Temp_Texture != NULL) && (Filter_Colour.Alpha > 0.01) ;
  727.         surface++, Temp_Texture = Temp_Texture->Next_Texture) {
  728.  
  729.       Make_Colour (&Surface_Colour, 0.0, 0.0, 0.0);
  730.       if (Quality <= 5) {
  731.          if (Ray_Intersection->Shape->Shape_Colour != NULL)
  732.             Surface_Colour = *Ray_Intersection->Shape->Shape_Colour;
  733.          else if (Ray_Intersection->Object->Object_Colour != NULL)
  734.             Surface_Colour = *Ray_Intersection->Object->Object_Colour;
  735.          else {
  736.             Make_Colour (&Surface_Colour, 0.5, 0.5, 0.5);
  737.             }
  738.          }
  739.       else
  740.          Colour_At (&Surface_Colour,
  741.                     Temp_Texture,
  742.                     &Ray_Intersection -> Point);
  743.  
  744.       /* We don't need to compute the lighting characteristics for shadow rays. */
  745.       if (!Shadow_Ray) {
  746.          Compute_Reflected_Colour (Ray,
  747.                                    Temp_Texture,
  748.                                    Ray_Intersection,
  749.                                    &Surface_Colour,
  750.                                    &Emitted_Colour);
  751.  
  752.          S_Alpha = 1.0 - Surface_Colour.Alpha;
  753.  
  754.          Colour->Red   += Emitted_Colour.Red *
  755.                              Filter_Colour.Alpha * S_Alpha;
  756.          Colour->Green += Emitted_Colour.Green *
  757.                              Filter_Colour.Alpha * S_Alpha;
  758.          Colour->Blue  += Emitted_Colour.Blue *
  759.                              Filter_Colour.Alpha * S_Alpha;
  760.          }
  761.  
  762. if (Options & DEBUGGING) {
  763.         printf ("Surface %d\n", surface);
  764.         printf ("   Emit: %6.4f %6.4f %6.4f %6.4f  Surf: %6.4f %6.4f %6.4f %6.4f\n",
  765.         Emitted_Colour.Red, Emitted_Colour.Green, Emitted_Colour.Blue, Emitted_Colour.Alpha,
  766.         Surface_Colour.Red, Surface_Colour.Green, Surface_Colour.Blue, Surface_Colour.Alpha);
  767.         printf ("   Filter_Colour:   %6.4f %6.4f %6.4f %6.4f  Final Colour: %6.4f %6.4f %6.4f %6.4f  \n",
  768.         Filter_Colour.Red, Filter_Colour.Green, Filter_Colour.Blue, Filter_Colour.Alpha,
  769.         Colour->Red, Colour->Green, Colour->Blue, Colour->Alpha);
  770.         }
  771.  
  772.       Filter_Colour.Red   *= Surface_Colour.Red;
  773.       Filter_Colour.Green *= Surface_Colour.Green;
  774.       Filter_Colour.Blue  *= Surface_Colour.Blue;
  775.  
  776.       Filter_Colour.Alpha *= Surface_Colour.Alpha;
  777.       }
  778.  
  779.    /* For shadow rays, we have the filter colour now - time to return */
  780.    if (Shadow_Ray) {
  781.  
  782.       if (Filter_Colour.Alpha < 0.01) {
  783.          Make_Colour (Colour, 0.0, 0.0, 0.0);
  784.          return;
  785.          }
  786.  
  787.       if (Texture->Object_Refraction > 0.0) {
  788.          Colour->Red *= Filter_Colour.Red * Texture->Object_Refraction * Filter_Colour.Alpha;
  789.          Colour->Green *= Filter_Colour.Green * Texture->Object_Refraction * Filter_Colour.Alpha;
  790.          Colour->Blue *= Filter_Colour.Blue * Texture->Object_Refraction * Filter_Colour.Alpha;
  791.          }
  792.       else {
  793.          Colour->Red *= Filter_Colour.Red * Filter_Colour.Alpha;
  794.          Colour->Green *= Filter_Colour.Green * Filter_Colour.Alpha;
  795.          Colour->Blue *= Filter_Colour.Blue * Filter_Colour.Alpha;
  796.          }
  797.       return;
  798.       }
  799.  
  800.    if ((Filter_Colour.Alpha > 0.01) && (Quality > 5)) {
  801.       Make_Colour (&Refracted_Colour, 0.0, 0.0, 0.0);
  802.  
  803.       if (Texture->Object_Refraction > 0.0) {
  804.          Normal (&Surface_Normal, (OBJECT *) Ray_Intersection -> Shape,
  805.                  &Ray_Intersection -> Point);
  806.  
  807.          if (Quality > 7) {
  808.             Perturb_Normal (&Surface_Normal, Texture,
  809.                             &Ray_Intersection->Point, &Surface_Normal);
  810.             }
  811.  
  812.          /* If the surface normal points away, flip its direction. */
  813.          VDot (Normal_Direction, Surface_Normal, Ray->Direction);
  814.          if (Normal_Direction > 0.0) {
  815.             VScale (Surface_Normal, Surface_Normal, -1.0);
  816.             }
  817.       
  818.          Refract (Texture, &Ray_Intersection -> Point, Ray,
  819.                   &Surface_Normal, &Refracted_Colour);
  820.          }
  821.       else
  822.          Refract (Texture, &Ray_Intersection->Point, Ray,
  823.                   NULL, &Refracted_Colour);
  824.  
  825.       Colour->Red += Filter_Colour.Red * Refracted_Colour.Red * Filter_Colour.Alpha;
  826.       Colour->Green += Filter_Colour.Green * Refracted_Colour.Green * Filter_Colour.Alpha;
  827.       Colour->Blue += Filter_Colour.Blue * Refracted_Colour.Blue * Filter_Colour.Alpha;
  828.       }
  829.  
  830.    if (Frame.Fog_Distance != 0.0)  {
  831.       Fog (Ray_Intersection->Depth, &Frame.Fog_Colour, Frame.Fog_Distance,
  832.            Colour);
  833.       }
  834.    }
  835.